package com.feihong.yw189.bluetooth.utils.djlm.newDJMLReader;

import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.Message;
import android.support.v4.content.LocalBroadcastManager;

import com.feihong.yw189.bluetooth.utils.util.HexUtil;

import java.io.IOException;
import java.io.OutputStream;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.net.SocketTimeoutException;
import java.util.Arrays;

/**
 * Created by Administrator on 2017/2/15.
 */
//身份证读卡命令基础管理类
public class DJML_IDCardReaderBase {
    Context m_ctx = null;
    public Handler m_ErrHandler = null;
    IOException m_e;

    DJML_IDCardReaderBase(Context ctx)
    {
        //m_ErrHandler = new ErrHandler(ctx.getMainLooper());
        m_ErrHandler = new Handler(ctx.getMainLooper()){
            @Override
            public void handleMessage(Message msg) {
                m_e = (IOException)msg.obj;
            }};
        m_ctx =ctx;
    }

    static int SeekFinePack(byte[] data, int nDataLen)
    {
        byte[] packHead = new byte[]{(byte)0xAA, (byte)0xAA, (byte)0xAA, (byte)0x96, (byte)0x69};
        if (nDataLen >= 9 && Arrays.equals(packHead, Arrays.copyOf(data, 5)))
        {
            int nLen = data[5] * 256 + data[6] + 7;
            if (nDataLen >= nLen)
            {
                return nDataLen;
            }
        }
        return -1;
    }

    //以TCP方式向服务器发送读卡的请求命令
    static int SendAndReceiveIDCommandTcp(Socket socketTcp, byte[] send, int nSendLen, byte[] receiveBuf, int nOvertime) throws IOException
    {
        int nReadLen = 0;
        socketTcp.getInputStream().skip( socketTcp.getInputStream().available());
        socketTcp.setSoTimeout(nOvertime);
        OutputStream out = socketTcp.getOutputStream();
        out.write(send, 0, nSendLen);
        out.flush();
        try {
            //nReadLen = socketTcp.getInputStream().read(receiveBuf);
            nReadLen = -1;
            for (int i = 0; i < receiveBuf.length; i++)
            {
                int nData = socketTcp.getInputStream().read();
                if (nData >= 0)
                {
                    receiveBuf[i] = (byte)nData;
                    nReadLen = SeekFinePack(receiveBuf, i + 1);
                    if (nReadLen >= 0)
                    {
                        break;
                    }
                }
            }
        } catch (SocketTimeoutException e) {
            return -1;
        }
        return nReadLen;
    }

    //以TCP方式向服务器发送读卡的请求命令
    static int SendAndReceiveIDCommandUDP(DatagramSocket socketUdp, SocketAddress sockAddr, byte[] send, int nSendLen, byte[] receiveBuf, int nOvertime) throws IOException
    {
        int nReadLen = 0;
        DatagramPacket sendPacket = new DatagramPacket(send, nSendLen, sockAddr);
        DatagramPacket recvPacket = new DatagramPacket(receiveBuf , receiveBuf.length);
        socketUdp.send(sendPacket);
        socketUdp.setSoTimeout(nOvertime);
        try {
            socketUdp.receive(recvPacket);
            nReadLen = recvPacket.getLength();
        } catch (SocketTimeoutException e) {
            return -1;
        }
        byte[] front = new byte[]{(byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0x96, 0x69};
        if (nReadLen >= 7 && Arrays.equals(Arrays.copyOf(receiveBuf, 5), front)) {
            int nLen = receiveBuf[5] * 256 + receiveBuf[6] + 7;
            if (nReadLen >= nLen) {
                return nReadLen;
            }
        }
        return -1;
    }

    //读卡器命令传输
    static int IDCardCommand(Socket socketTcp, DatagramSocket socketUdp, SocketAddress sockAddr, byte[] send,  int nSendLen, byte[] receiveBuf, byte[] SW, int nOvertime) throws IOException
    {
        int i = 0;
        byte nCheck = 0;
        for(i=5; i < send.length-1; i++)
        {
            nCheck ^= send[i];
        }
        send[send.length - 1] = nCheck;
        System.out.println("Reader send:" + HexUtil.bytesToHexString(send));
        int nRetLen = -1;
        if (socketTcp != null)
            nRetLen = SendAndReceiveIDCommandTcp(socketTcp, send, nSendLen, receiveBuf,  nOvertime );
        else
            nRetLen = SendAndReceiveIDCommandUDP(socketUdp, sockAddr, send, nSendLen, receiveBuf, nOvertime);

        if (nRetLen >= 10 && SW != null)
        {
            SW[0] = receiveBuf[7];
            SW[1] = receiveBuf[8];
            SW[2] = receiveBuf[9];
        }
        if (nRetLen >= 0)
            System.out.println("Reader rev:"+ HexUtil.bytesToHexString(receiveBuf, nRetLen));
        else
            System.out.println("Reader rev: null");
        return nRetLen;
    }

    /////////////////////////////////////////////////////////////////////////
    //初始化读卡器的读卡命令长度
    int InitSAM(Socket socketTCP, DatagramSocket socketUdp, SocketAddress sockAddr, int nFrameLen, byte[] SW,  int nOverTime) throws IOException
    {
        byte[] send = new byte[]{(byte)0xAA, (byte)0xAA, (byte)0xAA, (byte)0x96, 0x69, 0x00, 0x04, 0x61, (byte)0xff, 0x24, 0x22};
        byte[] receiveBuf = new byte[256];
        send[9] = (byte)nFrameLen;
        int nLen = IDCardCommand(socketTCP, socketUdp, sockAddr, send, send.length, receiveBuf, SW, nOverTime);
        broadcastUpdate("Init SAM(" + nLen + ")" + HexUtil.bytesToHexString(SW));
        if (nLen >= 0)
            return 0;
        else
            return -1;
        //throw new IOException("comm error");
    }

    //开始寻卡
    int StartFindIDCard(Socket socketTCP, DatagramSocket socketUdp, SocketAddress sockAddr, byte[] SW, int nOverTime) throws IOException
    {
        byte[] szSend1 = new byte[]{(byte)0xAA,(byte)0xAA,(byte)0xAA,(byte)0x96,0x69,0x00,0x03,0x20,0x01,0x22};
        byte[] receiveBuf = new byte[256];
        int nLen = IDCardCommand(socketTCP, socketUdp, sockAddr, szSend1, szSend1.length, receiveBuf, SW,  nOverTime);
        broadcastUpdate("Find Card(" + nLen + ")" + HexUtil.bytesToHexString(SW) );
        if (nLen >= 0)
            return 0;
        else
            return -1;
        //throw new IOException("comm error");
    }

    //选择卡片
    int SelectIDCard(Socket socketTCP, DatagramSocket socketUdp, SocketAddress sockAddr, byte[] SW, int nOverTime) throws IOException
    {
        byte[] szSend2 = new byte[]{(byte)0xAA,(byte)0xAA,(byte)0xAA,(byte)0x96,0x69,0x00,0x03,0x20,0x02,0x21};
        byte[] receiveBuf = new byte[256];
        int nLen = IDCardCommand(socketTCP, socketUdp, sockAddr, szSend2, szSend2.length, receiveBuf, SW, nOverTime);
        broadcastUpdate("Select Card(" + nLen + ")" + HexUtil.bytesToHexString(SW) );
        if (nLen >= 0)
            return 0;
        else
            return -1;
        //throw new IOException("comm error");
    }

    //读取卡片的基础信息，包含照片信息。
    int ReadBaseMsg(Socket socketTCP, DatagramSocket socketUdp, SocketAddress sockAddr, byte[] retData,  byte[] SW, int nOverTime) throws IOException
    {
        byte[] szSend3 = new byte[]{(byte)0xAA,(byte)0xAA,(byte)0xAA,(byte)0x96,0x69,0x00,0x03,0x30,0x01,0x32};
        byte[] receiveBuf = new byte[2048];
        int nLen = IDCardCommand(socketTCP, socketUdp, sockAddr, szSend3, szSend3.length, receiveBuf, SW,  nOverTime);
        broadcastUpdate("Read Card(" + nLen + ")" + HexUtil.bytesToHexString(SW));
        if (nLen >= 0) {
            if (nLen >= 1295) {
                int nRetLen = receiveBuf[5] * 256 + receiveBuf[6] - 4;
                System.arraycopy(receiveBuf, 10, retData, 0, nRetLen);
                return 0;
            }
            return 3;
        }
        else
            return -1;
        //throw new IOException("comm error");
    }

    //身份证读卡流程
    int ReadCardRoutine(Socket socketTCP, DatagramSocket socketUdp, SocketAddress sockAdd, byte[]  revData, byte[] SW, int nWaiteTime) throws IOException
    {
        int i;
        int nRet = -1;
        long nBeginTime = System.currentTimeMillis();
        for (i = 0; i < 3||System.currentTimeMillis() < nBeginTime + nWaiteTime;i++) {
            nRet = StartFindIDCard(socketTCP, socketUdp, sockAdd, SW, 800);;
            if (nRet != 0 && i >= 3)
                break;
            else if (nRet == 0 && (SW[0] == 0 && SW[1] == 0 && SW[2] == (byte)0x9F))
                break;
            if (i % 3 == 2 && i >= 3)
            {
                try{
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
            if (m_e != null)
                throw m_e;
        }
        if (nRet < 0) {
            throw new IOException("comm Error");
        }
        else if (nRet == 0 && (SW[0] == 0 && SW[1] == 0 && SW[2] == (byte)0x9F))
        {
            for (i = 0; i < 3; i++)
            {
                Arrays.fill(SW, (byte)0);
                nRet = SelectIDCard(socketTCP, socketUdp, sockAdd, SW, 800);
                if (nRet != 0)
                    ;//break;
                else if ((SW[0] == 0 && SW[1] == 0 && (SW[2] == (byte)0x90 || SW[2] == (byte)0x9F)))
                    break;
                if (m_e != null)
                    throw m_e;
            }
            try{
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            if (nRet == 0)
            {
                Arrays.fill(SW, (byte)0);
                nRet = ReadBaseMsg(socketTCP, socketUdp, sockAdd, revData, SW, 30000);
                if (nRet == 0  && (SW[0] == 0 && SW[1] == 0 && SW[2] == (byte)0x90))
                {
                    return 0;
                }
                else
                {
                    String strError = "ReadCard Error " + HexUtil.bytesToHexString(SW);
                    throw new IOException(strError);
                }
            }
            if (nRet < 0)
            {
                throw new IOException("comm Error");
            }
        }
        else if (nRet == 0  && (SW[0] == 0 && SW[1] == 0 && SW[2] == (byte)0x80))
        {
            throw new IOException("no Find Card!");
        }
        else
        {
            throw new IOException("Find Card Error " + HexUtil.bytesToHexString(SW));
        }
        return 2;
    }
    /*
    static byte[] ReadCard(Socket socketTCP, DatagramSocket socketUdp, SocketAddress sockAddr, int nOverTime) throws IOException
    {
        byte[] szSend0 = new byte[]{(byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0x96, 0x69, 0x00, 0x04, 0x61, (byte) 0xFF, 0x38, 0x22};
        byte[] szSend1 = new byte[]{(byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0x96, 0x69, 0x00, 0x03, 0x20, 0x01, 0x22};
        byte[] szSend2 = new byte[]{(byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0x96, 0x69, 0x00, 0x03, 0x20, 0x02, 0x21};
        byte[] szSend3 = new byte[]{(byte) 0xAA, (byte) 0xAA, (byte) 0xAA, (byte) 0x96, 0x69, 0x00, 0x03, 0x30, 0x01, 0x32};
        byte[] SW = new byte[3];
        byte[] ret = IDCardCommand(socketTCP, socketUdp, sockAddr, szSend1, SW, nOverTime);
        broadcastUpdate("Find Card");
        if (ret != null && !(ret.length >= 15 && ret[7] == 0 && ret[8] == 0 && ret[9] == (byte) 0x9F)) {
            ret = IDCardCommand(socketTCP, socketUdp, sockAddr, szSend1, SW, nOverTime);
            broadcastUpdate("Find Card");
        }
        if (ret != null && (ret.length >= 15 && ret[7] == 0 && ret[8] == 0 && ret[9] == (byte) 0x9F)) {
            ret = IDCardCommand(socketTCP, socketUdp, sockAddr, szSend2, SW, nOverTime);
            broadcastUpdate("Select Card");
            if (ret != null && !(ret.length >= 15 && ret[7] == 0 && ret[8] == 0 && ret[9] == (byte) 0x9F)) {
                ret = IDCardCommand(socketTCP, socketUdp, sockAddr, szSend2, SW, nOverTime);
                broadcastUpdate("Select Card");
            }
            if (ret != null) {
                broadcastUpdate("Read Card");
                ret = IDCardCommand(socketTCP, socketUdp, sockAddr, szSend3, SW, 20000);
                if (ret != null && (ret.length >= 1295 && ret[7] == 0 && ret[8] == 0 && ret[9] == (byte) 0x90)) {
                    int nRetLen = ret[5] * 256 + ret[6] - 4;
                    return Arrays.copyOfRange(ret, 10, nRetLen + 10);
                }
            }
        }
        return null;
    }
    */

    //启动一次读卡流程
    public int ReadCardOneCard(byte[] revData, byte[] SW, int nWaiteTime) throws IOException
    {
        int nRet = -1;
        ////////////////////////////////////////////////////////////
        InitSAM(socketTcp, socketUdp, sockAddr, 24, null, 800);
        nRet = ReadCardRoutine(socketTcp, socketUdp, sockAddr, revData, SW, nWaiteTime);
        /////////////////////////////////////////////////////////
        return nRet;
    }

    DatagramSocket socketUdp = null;
    Socket socketTcp = null;
    SocketAddress sockAddr = null;
    public void InitConnect(String strIP, int nPort, boolean bUDP) throws IOException
    {
        System.out.println("init reader port!");
        socketTcp = null;
        socketUdp = null;
        sockAddr = new InetSocketAddress(strIP, nPort);

        if (bUDP) {
            socketUdp = new DatagramSocket();
        } else {
            socketTcp = new Socket();
            //socketTcp.setKeepAlive(true);
            socketTcp.setTcpNoDelay(true);
            socketTcp.setSoTimeout(200);
            socketTcp.connect(sockAddr);
        }
    }

    public void CloseConnect()
    {
        System.out.println("close reader port!");
        try
        {
            if(socketTcp!=null)
            {
                socketTcp.close();
                socketTcp = null;
            }
            if(socketUdp!=null)
            {
                socketUdp.close();
                socketUdp = null;
                sockAddr = null;
            }
        }
        catch (Exception e)
        {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    //广播输出调试信息
    private void broadcastUpdate(String strInfo) {
        if (m_ctx != null) {
            final Intent intent = new Intent("IDCardReader");
            intent.putExtra("IDCardReader", strInfo);
            LocalBroadcastManager.getInstance(m_ctx).sendBroadcast(intent);
            System.out.println(strInfo);
        }
    }


}
